package com.market.plus.ocm.service;

import java.awt.Dimension;
import java.awt.image.BufferedImage;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;

import javax.imageio.ImageIO;

import org.imgscalr.Scalr;
import org.imgscalr.Scalr.Method;
import org.springframework.stereotype.Service;
import org.springframework.web.multipart.commons.CommonsMultipartFile;

import com.market.plus.ocm.model.MetadataScaleFile;

@Service("scaleImageService")
public class ScaleImageServiceImpl implements ScaleImageService {

   public static final int DEFAULT_SCALE_SMALL_WIDTH=64;

   public static final int DEFAULT_SCALE_MEDIUM_WIDTH=200;

   public static final int DEFAULT_SCALE_LIMIT_SIZE=50000;

   public MetadataScaleFile[] scaleMediumAndSmall(CommonsMultipartFile file) throws Exception {
      MetadataScaleFile[] commonScaleFiles = scale(file.getInputStream(), file.getContentType());
      commonScaleFiles[0].setOriginalFile(file);
      commonScaleFiles[1].setOriginalFile(file);
      return commonScaleFiles;
   }

   public MetadataScaleFile scaleMedium(InputStream file, String mimeType) throws Exception {
      BufferedImage bufferedImage = ImageIO.read(file);
      if (bufferedImage != null){
         BufferedImage mediumThumbnail = scaleMedium(bufferedImage);
         MetadataScaleFile medium = getMetadataScaleFile(mediumThumbnail, mimeType);
         return medium;
      }
      return null;
   }

   public MetadataScaleFile scaleMedium(byte[] bytes, String mimeType) throws Exception {
      ByteArrayInputStream in = new ByteArrayInputStream(bytes);
      return scaleMedium(in, mimeType);
   }

   public MetadataScaleFile scaleSmall(InputStream file, String mimeType) throws Exception {
      BufferedImage bufferedImage = ImageIO.read(file);
      if (bufferedImage != null){
         BufferedImage smallThumbnail = scaleSmall(bufferedImage);
         MetadataScaleFile small = getMetadataScaleFile(smallThumbnail, mimeType);
         return small;
      }
      return null;
   }

   public MetadataScaleFile scaleSmall(byte[] bytes, String mimeType) throws Exception {
      ByteArrayInputStream in = new ByteArrayInputStream(bytes);
      return scaleSmall(in, mimeType);
   }

   private MetadataScaleFile[] scale(InputStream inputStream, String mimeType) throws Exception{
      BufferedImage bufferedImage = ImageIO.read(inputStream);
      BufferedImage mediumThumbnail = scaleMedium(bufferedImage);
      BufferedImage smallThumbnail = scaleSmall(mediumThumbnail);
      MetadataScaleFile medium = getMetadataScaleFile(mediumThumbnail, mimeType);
      MetadataScaleFile small = getMetadataScaleFile(smallThumbnail, mimeType);
      MetadataScaleFile[] commonScaleFiles = new MetadataScaleFile[2];
      commonScaleFiles[0] = medium;
      commonScaleFiles[1] = small;
      return commonScaleFiles;
   }

   private BufferedImage scaleSmall(BufferedImage bufferedImage) throws IOException{
      BufferedImage thumbnail = Scalr.resize(bufferedImage, Method.ULTRA_QUALITY, Scalr.Mode.FIT_TO_WIDTH, getFitSmallWidth(bufferedImage.getWidth()));
      return thumbnail;
   }
   
   private BufferedImage scaleMedium(BufferedImage bufferedImage) throws IOException{
      BufferedImage thumbnail = Scalr.resize(bufferedImage, Method.ULTRA_QUALITY, Scalr.Mode.FIT_TO_WIDTH, getFitWidth(bufferedImage.getWidth()));
      return thumbnail;
   }

   private int getFitWidth(int width){
      int expected = (width < DEFAULT_SCALE_MEDIUM_WIDTH) ? width : DEFAULT_SCALE_MEDIUM_WIDTH;
      return expected;
   }

   private int getFitSmallWidth(int width){
      int expected = (width < DEFAULT_SCALE_SMALL_WIDTH) ? width : DEFAULT_SCALE_SMALL_WIDTH;
      return expected;
   }

   private MetadataScaleFile getMetadataScaleFile(BufferedImage bufferedImage, String mimeType) throws Exception{
      ByteArrayOutputStream baos = new ByteArrayOutputStream();
      ImageIO.write(bufferedImage, MimeTypeSupport.convertFormatName(mimeType), baos);
      baos.flush();
      byte[] bs = baos.toByteArray();
      baos.close();
      MetadataScaleFile metadataScaleFile = new MetadataScaleFile();
      metadataScaleFile.setHeight(bufferedImage.getHeight());
      metadataScaleFile.setWidth(bufferedImage.getWidth());
      metadataScaleFile.setSize(Long.parseLong(""+bs.length));
      metadataScaleFile.setBytes(bs);
      return metadataScaleFile;
   }

   public Dimension getMetadataScaleFile(InputStream inputStream) throws IOException{
      Dimension dimension = SimpleImageInfo.processStream(inputStream);
      return dimension;
   }
}
